package com.scs.application.modules.base.controller;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import cn.smallbun.screw.core.Configuration;
import cn.smallbun.screw.core.engine.EngineConfig;
import cn.smallbun.screw.core.engine.EngineFileType;
import cn.smallbun.screw.core.engine.EngineTemplateType;
import cn.smallbun.screw.core.execute.DocumentationExecute;
import cn.smallbun.screw.core.process.ProcessConfig;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Maps;
import com.scs.application.config.HikariPoolManager;
import com.scs.application.core.consts.ErrorCode;
import com.scs.application.core.exception.BusinessException;
import com.scs.application.core.export.entity.ExportParams;
import com.scs.application.core.export.service.ExportService;
import com.scs.application.core.export.service.ImportService;
import com.scs.application.core.mvc.controller.CrudController;
import com.scs.application.core.query.QueryContext;
import com.scs.application.core.query.QueryContextHolder;
import com.scs.application.core.query.QueryGenerator;
import com.scs.application.core.utils.*;
import com.scs.application.modules.base.dto.ExportHeadDTO;
import com.scs.application.modules.base.entity.Dept;
import com.scs.application.modules.base.service.DeptService;
import com.scs.application.modules.base.util.CommonService;
import com.scs.application.modules.project.Const;
import com.scs.application.modules.report.entity.Config;
import com.scs.application.modules.report.entity.GridField;
import com.scs.application.modules.report.handler.BeforeReport;
import com.scs.application.modules.report.service.ConfigService;
import com.scs.application.modules.report.service.impl.ConfigServiceImpl;
import com.scs.application.modules.sys.adapter.DictAdapter;
import com.scs.application.modules.sys.model.RestResult;
import com.scs.application.modules.sys.service.FileService;
import com.scs.application.modules.sys.service.PrinterService;
import com.scs.application.modules.sys.utils.UtilDatabase;
import com.zebra.sdk.comm.Connection;
import com.zebra.sdk.comm.ConnectionException;
import com.zebra.sdk.comm.TcpConnection;
import org.apache.catalina.connector.ClientAbortException;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ClassPathResource;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.sql.SQLException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 院方科室 前端控制器
 * </p>
 */
@RestController
@RequestMapping("/tool")
public class ToolController extends CrudController<DeptService, Dept> {
    @Value("${spring.datasource.dynamic.datasource.master.url}")
    String url;
    @Value("${spring.datasource.dynamic.datasource.master.driver-class-name}")
    String driverClassName;
    @Value("${spring.datasource.dynamic.datasource.master.username}")
    String username;
    @Value("${res.real-path}")
    private String resPath;

    @Autowired
    FileService fileService;


    @Autowired
    PrinterService printerService;
    @Autowired
    ConfigService configService;

    @Autowired
    private DictAdapter dictAdapter;

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Autowired
    private ExportService exportService;

    /**
     * @Description：生成表结构
     */
    @PostMapping(value = "/tableStructureBuild", produces = "application/json; charset=utf-8")
    public RestResult tableStructureBuild(@RequestBody Map<String, String> reqData) throws IOException, SQLException {
        RestResult result = RestResult.ok("操作成功");
        boolean isPreview = Boolean.valueOf(reqData.get("isPreview"));
        //生成文件类型
        String buildType = reqData.get("buildType");
        String appName = "fortec-bm", title = "数据库设计文档", version = "1.0";
        String tableStructureBuildDir = resPath + Const.FILE_TMP;
        File savePath = new File(tableStructureBuildDir);
        if (!savePath.exists()) savePath.mkdirs();

        HikariPoolManager.getInstance(url, driverClassName, username, UtilDatabase.getPassword(username));

        EngineFileType engineFileType = EngineFileType.HTML;

        if ("doc".equalsIgnoreCase(buildType)) engineFileType = EngineFileType.WORD;

        HikariPoolManager.start();

        //生成配置
        EngineConfig engineConfig = EngineConfig.builder()
                //生成文件路径
                .fileOutputDir(tableStructureBuildDir)
                //打开目录
                .openOutputDir(false)
                //文件类型
                .fileType(engineFileType)
                //生成模板实现
                .produceType(EngineTemplateType.freemarker).build();

        //筛选表
        ArrayList<String> selectTableS = new ArrayList<>();
        if (!StringUtils.isBlank(reqData.get("tablePrefix"))) selectTableS.add(reqData.get("tablePrefix"));

        ProcessConfig processConfig = ProcessConfig.builder()
                .designatedTablePrefix(selectTableS)
                .build();
        //配置
        Configuration config = Configuration.builder()
                //版本
                .version(version)
                //描述
                .description(title)
                //数据源
                .dataSource(HikariPoolManager.getdDataSource())
                //生成配置
                .engineConfig(engineConfig)
                //生成配置
                .produceConfig(processConfig).build();


        //执行生成
        new DocumentationExecute(config).execute();
        HikariPoolManager.stop();

        //需要预览，则返回文件内容
        String fileName = appName + "_" + title + "_" + version + "." + buildType;
        String fileAbsPath = tableStructureBuildDir + File.separator + fileName;
        if (isPreview) {
            String stringFile = FileUtils.readFile(fileAbsPath);
            result.setData(stringFile);
        } else {
            result.setData("/" + Const.FILE_TMP + fileName);
        }
        return result;
    }

    /**
     * 多文件上传
     *
     * @Description：多文件上传 【需要统一存放】
     */
    @RequestMapping(value = "/uploadMore", method = RequestMethod.POST)
    public RestResult uploadMore(@RequestParam Map<String, String> reqData, @RequestParam("file") MultipartFile file, HttpServletRequest request) {
        RestResult result = RestResult.ok("文件上传成功");
        //文件保存路径
        String fileSavePath = reqData.get("fileSavePath"), fileAccessPath;
        String refTable = reqData.get("fileRefTable");
        String refId = reqData.get("fileRefId");
        if (StringUtils.isBlank(fileSavePath)) fileSavePath = "tmp";
        fileSavePath += "/";
        fileAccessPath = fileSavePath;
        fileSavePath = resPath + fileSavePath;

        BufferedOutputStream stream = null;
        JSONObject fileOb;
        String fileName = UUID.randomUUID() + "." + FileUtils.getFileExtension(file.getOriginalFilename());
        fileOb = new JSONObject();
        fileOb.put("name", file.getOriginalFilename());
        fileOb.put("url", resPath + fileAccessPath + fileName);
        fileOb.put("filePath", "/res/" + fileAccessPath + fileName);
        try {
            FileUtils.mkdirs(fileSavePath);
            if (StringUtils.isBlank(refTable)) throw new BusinessException("缺少参数【refTable】");
            if (StringUtils.isBlank(refId)) throw new BusinessException("缺少参数【refId】");

            byte[] bytes = file.getBytes();
            stream = new BufferedOutputStream(new FileOutputStream(
                    new File(fileSavePath + fileName)));//设置文件路径及名字
            stream.write(bytes);// 写入
            stream.close();

            com.scs.application.modules.sys.entity.File fileSave = new com.scs.application.modules.sys.entity.File();
            fileSave.setRefId(refId);
            fileSave.setRefTable(refTable);
            fileSave.setFileName(file.getOriginalFilename());
            fileSave.setFilePath("/res/" + fileAccessPath + fileName);
            fileService.save(fileSave);
        } catch (Exception e) {
            result.setMsg("文件上传失败," + e.getMessage());
            result.setCode(ErrorCode.COMMON_ERROR);
        }
        result.setData(fileOb);
        return result;
    }

    /**
     * @Description：图片base64上传 【需要统一存放】
     */
    @RequestMapping(value = "/uploadImg", method = RequestMethod.POST)
    public RestResult<String> uploadImg(@RequestBody Map<String, String> reqData) {
        RestResult result = RestResult.ok("文件上传成功");
        //文件保存路径
        String fileSavePath = reqData.get("fileSavePath"), fileAccessPath;
        String refTable = reqData.get("fileRefTable");
        String refId = reqData.get("fileRefId");
        String fileRefIdOnlyOne = reqData.get("fileRefIdOnlyOne");
        String base64Str = reqData.get("base64Str");
        if (StringUtils.isBlank(fileSavePath)) fileSavePath = "tmp";
        fileSavePath += "/";
        fileAccessPath = fileSavePath;
        fileSavePath = resPath + fileSavePath;

        StringBuffer fileName = new StringBuffer();
        fileName.append(UUID.randomUUID().toString().replaceAll("-", ""));
        if (base64Str.indexOf("data:image/png;") != -1) {
            base64Str = base64Str.replace("data:image/png;base64,", "");
            fileName.append(".png");
        } else if (base64Str.indexOf("data:image/jpeg;") != -1) {
            base64Str = base64Str.replace("data:image/jpeg;base64,", "");
            fileName.append(".jpeg");
        } else {
            result.setMsg("文件上传失败,请选择.png.jpg格式的图片");
            result.setCode(ErrorCode.COMMON_ERROR);
            return result;
        }

        logger.debug("uploadImg.fileSavePath={}", fileSavePath);
        logger.debug("uploadImg.fileName={}", fileName.toString());
        File file = new File(fileSavePath, fileName.toString());
        byte[] fileBytes = Base64.getDecoder().decode(base64Str);
        try {
            FileUtils.mkdirs(fileSavePath);
            FileUtils.writeByteArrayToFile(file, fileBytes);
            //不为空的话，进行文件记录
            if (StringUtils.isNotBlank(refId)) {

                //同一个id只保留一个文件记录的时候，先删掉其他的
                if ("1".equals(fileRefIdOnlyOne)) {
                    QueryWrapper queryWrapper = Wrappers.query();
                    queryWrapper.eq("ref_id", refId);
                    fileService.remove(queryWrapper);
                }

                com.scs.application.modules.sys.entity.File fileSave = new com.scs.application.modules.sys.entity.File();
                fileSave.setRefId(refId);
                fileSave.setRefTable(refTable);
                fileSave.setFileName(fileName.toString());
                fileSave.setFilePath("/res/" + fileAccessPath + fileName);
                fileService.save(fileSave);
            }
        } catch (IOException e) {
            result.setMsg("文件上传失败," + e.getMessage());
            result.setCode(ErrorCode.COMMON_ERROR);
        }
        result.setData("/res/" + fileAccessPath + fileName);
        return result;
    }

    /**
     * @param fileType : 文件后缀
     * @param fileName : 文件名，不包含后缀
     * @Description：下载 static/download目录下的文件
     */
    @GetMapping(value = "download/{fileType}/{fileName}")
//    ,produces = {"application/vnd.android.package-archive"}
    public String downloadFile(@PathVariable String fileType, @PathVariable String fileName, HttpServletRequest request, HttpServletResponse response) {
        if (StringUtils.isBlank(fileType)) return "下载失败，缺少参数【fileType】";
        if (StringUtils.isBlank(fileName)) return "下载失败，缺少参数【fileName】";
        String fileAllName = fileName + "." + fileType;
        //设置文件路径
        ClassPathResource classPathResource = new ClassPathResource("static/download/" + fileAllName);
        if (!classPathResource.exists()) return "下载失败，资源不存在";

        InputStream inputStream = null;
        String fileAllNameNew = fileAllName;
        long inputStreamLength = 0;

        String tmpFilePath = resPath + "tmp/downloadFile_" + System.currentTimeMillis();
        File tmpFile = new File(tmpFilePath);
        try {
            inputStream = classPathResource.getInputStream();
            fileAllNameNew = new String(fileAllName.getBytes("GBK"), "ISO-8859-1");

            FileUtils.copyToFile(inputStream, tmpFile);
            inputStreamLength = tmpFile.length();
        } catch (IOException e) {
            logger.error("downloadFile.classPathResource.getInputStream()", e);
        }
        if (inputStream == null) {
            //删除临时文件
            FileUtils.deleteFile(tmpFilePath);
            return "文件下载失败，请稍候重试";
        }

        logger.debug("downloadFile.fileAllNameNew={}", fileAllNameNew);
        logger.debug("downloadFile.inputStreamLength={}", inputStreamLength);
        logger.debug("downloadFile.classPathResource.getPath={}", classPathResource.getPath());
        //apk格式
        if ("apk".equalsIgnoreCase(fileType)) {
            response.setContentType("application/vnd.android.package-archive");
            response.setHeader("content-type", "application/vnd.android.package-archive");
        } else {
            response.setContentType("application/octet-stream");//
            response.setHeader("content-type", "application/octet-stream");
        }
        response.addHeader("Content-Length", "" + inputStreamLength);
        response.setHeader("Content-Disposition", "attachment;fileName=" + fileAllNameNew);// 设置文件名
        byte[] buffer = new byte[1024];
        BufferedInputStream bis = null;
        FileInputStream fis = null;
        try {

            fis = new FileInputStream(tmpFile);
            bis = new BufferedInputStream(fis);
            OutputStream os = response.getOutputStream();
            int i = bis.read(buffer);
            while (i != -1) {
                os.write(buffer, 0, i);
                i = bis.read(buffer);
            }

        } catch (Exception e) {
            logger.error("downloadFile.readfile():{}", e);
        } finally {
            if (bis != null) {
                try {
                    bis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    logger.error("downloadFile.inputStream.close", e);
                }
            }
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    logger.error("downloadFile.fis.close", e);
                }
            }
            //删除临时文件
            FileUtils.deleteFile(tmpFilePath);
        }
        return "下载失败，请稍候重试";
    }

    /**
     * @param docxPath :  /res/cfg_parameter/1.docx
     * @Description： 将docx转换成pdf返回
     */
    @GetMapping(value = "getPdfFromDocx")
    public RestResult getPdfFromDocx(String docxPath) {
        RestResult restResult = RestResult.ok();

        try {
            FileUtils.mkdirs(resPath + "tmp/pdf");
            String pathAccess = "tmp/pdf/tmp_" + System.currentTimeMillis() + ".pdf";
            String tmpFilePath = resPath + pathAccess;
            WordUtils.convertDocxToPdf(resPath + docxPath.substring(5, docxPath.length()), tmpFilePath);
            restResult.setData("/res/" + pathAccess);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return restResult;
    }

    /***
     * @Description：根据 关联信息查询文件列表
     */
    @GetMapping("/getFilesByRef")
    public RestResult getFilesByRef(String fileRefTable, String fileRefId) {
        if (StringUtils.isBlank(fileRefTable)) return RestResult.error("附件查询失败,缺少参数【refTable】");
        if (StringUtils.isBlank(fileRefId)) return RestResult.error("附件查询失败,缺少参数【refId】");
        List<com.scs.application.modules.sys.entity.File> files = fileService.list(Wrappers.<com.scs.application.modules.sys.entity.File>query().eq("ref_table", fileRefTable).eq("ref_id", fileRefId)
        );
        return RestResult.ok("附件查询成功", files);
    }

    /***
     * @Description：根据 删除文件
     */
    @GetMapping("/delFilesByRef")
    public RestResult delFilesByRef(String fileId) {
        if (StringUtils.isBlank(fileId)) return RestResult.error("附件删除失败,缺少参数【fileId】");

        com.scs.application.modules.sys.entity.File fileDel = fileService.getOne(Wrappers.<com.scs.application.modules.sys.entity.File>query().eq("id", fileId));
        if (fileDel != null) {
            fileService.removeById(fileDel.getId());
            FileUtils.deleteFile(resPath + fileDel.getFilePath().replaceFirst("/res/", ""));
        }
        return RestResult.ok("附件删除成功");
    }

    /**
     * @Description：RFID打印
     */
    @PostMapping(value = "/printRFID", produces = "application/json; charset=utf-8")
    public RestResult printRFID(@RequestBody Map<String, String> param) {
        return printerService.printRFID(JSON.parseArray(param.get("snArr")), param.get("printerId"));
    }

    /**
     * @Description：测试打印机是否联通
     */
    @GetMapping(value = "/printTest", produces = "application/json; charset=utf-8")
    public RestResult printTest(String url, int port) {
        if (StringUtils.isBlank(url)) throw new BusinessException("缺少参数【printTest】");
        if (port < 1) throw new BusinessException("缺少参数【port】");
        Connection printerConnection = null;
        printerConnection = new TcpConnection(url, port);
        RestResult result = RestResult.ok("打印机可以连接");
        try {
            printerConnection.open();
        } catch (ConnectionException e) {
            result.setCode(ErrorCode.COMMON_ERROR);
            result.setMsg("打印机无法连接" + e.getMessage());
            result.setSuccess(false);
        } finally {
            try {
                if (printerConnection != null) printerConnection.close();
            } catch (Exception e) {
                logger.error("printTest.error", e);
            }
        }
        return result;
    }

    /**
     * 查询前置方法，执行前置方法，替换columnSql数据源中的  %filterSql%
     */
    private String beforeQuerycColumnSql(Config config, Map<String, Object> param) {
        String sqlNew = config.getColumnSql();
        logger.debug("ConfigServiceImpl.beforeQuerycColumnSql.sqlOld={}", sqlNew);
        //有前置方法
        if (StringUtils.isNotBlank(config.getPreFunColumnSql())) {
            try {
                sqlNew = SpringUtils.invokeMethod(BeforeReport.class, config.getPreFunColumnSql(), sqlNew, param) + "";
            } catch (Exception e) {
                e.printStackTrace();
                throw new BusinessException("执行前置方法%s失败，原因:%s", config.getPreFun(), e.getMessage());
            }
        }
        //替换数据源中的  %filterSql%
        sqlNew = sqlNew.replaceAll("%filterSql%", " ");
//        logger.debug("ConfigServiceImpl.beforeQuerycColumnSql.sqlNew={}",sqlNew);
        return sqlNew;
    }

    /**
     * 导出数据
     */
    @PostMapping("/export")
    public RestResult export(HttpServletResponse response, HttpServletRequest request, @RequestBody Map<String, Object> reqData) throws Exception {
        RestResult restResult = RestResult.ok();
        String type = (String) reqData.get("type"), code = (String) reqData.get("code"), queryString = (String) reqData.get("queryString"), orderBy = (String) reqData.get("orderBy");
        String exportFooterSignArrStr = (String) reqData.get("exportFooterSignArrStr");
        String exportFooterSumArrStr = (String) reqData.get("exportFooterSumArrStr");
        JSONArray exportFooterSignArr = null, exportFooterSumArr = null;
        if (StringUtils.isNotBlank(exportFooterSignArrStr))
            exportFooterSignArr = JSONArray.parseArray(exportFooterSignArrStr);
        if (StringUtils.isNotBlank(exportFooterSumArrStr))
            exportFooterSumArr = JSONArray.parseArray(exportFooterSumArrStr);

        HSSFWorkbook workbook = new HSSFWorkbook();
        String fileName = "", fileNameAll = "", sheetName = "";
        List<ExportHeadDTO> exportHeadDTOList1 = new ArrayList<ExportHeadDTO>();
        List<ExportHeadDTO> exportHeadDTOListAll = new ArrayList<ExportHeadDTO>();
        List<ExportHeadDTO> exportHeadDTOList2 = new ArrayList<ExportHeadDTO>();
        List<Map<String, Object>> exporDataList = new ArrayList<Map<String, Object>>();
        List<Map<String, Object>> exporSumDataList = new ArrayList<Map<String, Object>>();
        ExportHeadDTO exportHeadDTO = null;
        String sheet1Title = null, sheet1SubTitle = null;

        //二级列第一列左边空列数量
        final int[] leftEmptyColNum = {0};

        //报表导出
        Config config = configService.getOne(Wrappers.<Config>query().eq("code", code).last("limit 1"));
        if ("report".equalsIgnoreCase(type)) {
            if (config == null) throw new BusinessException("未找到报表标识%s", code);

            List<GridField> gridFields = configService.getGridFields(config.getId());
            if (gridFields == null || gridFields.size() < 1) throw new BusinessException("报表标识%s没有可用导出字段", code);

            sheet1Title = config.getName();
            sheet1SubTitle = config.getSubtitle();

            //数据列
            ConfigServiceImpl.FetchResult fetchResult = configService.fetchSqlData(config, false, reqData);

            if (config.getFlagDynamicColumn()||config.getFlagFixedColumn()){
                //动态列字段
                if (config.getFlagFixedColumn()) {
                    gridFields= CommonService.reportFixColumnParents(config,gridFields);
                }else {
                gridFields = CommonService.reportGetDynamicColumns(config, reqData, gridFields, fetchResult.getData());
                }
                //动态列数据
                if (config.getFlagFixedColumn()) {
                    fetchResult.setData(CommonService.reportFixColumnParentData(config,gridFields,reqData,fetchResult.getData()));
                }else {
                fetchResult.setData(CommonService.reportGetDynamicData(config, gridFields, reqData, fetchResult.getData()));
                }
                if (gridFields != null && gridFields.size() > 0){
                    //一级表头
                    List<GridField> finalGridFields = gridFields;
                    final boolean[] fields2Flag = {true};
                    finalGridFields.stream().filter(gridField ->StringUtils.isBlank(gridField.getParentField()) &&  (gridField.getFlagGroup() == null || !gridField.getFlagGroup()) && gridField.getFlagShow() !=null && gridField.getFlagShow()).forEach(gridField1 -> {
                        ExportHeadDTO exportHeadDTO1 = new ExportHeadDTO();
                        exportHeadDTO1.setName(gridField1.getField()).setText(gridField1.getLabel()).setQueryType(gridField1.getQueryType()).setDict(gridField1.getDict());
                        exportHeadDTO1.setRowspan(2).setColspan(1);
                        //一级表头对应的二级表头
                        List<GridField> gridFields2 = finalGridFields.stream().filter(gridField2 -> gridField1.getField().equals(gridField2.getGroupField()) || gridField1.getField().equals(gridField2.getParentField()) ).collect(Collectors.toList());
                        List<ExportHeadDTO> exportHeadDTOList2Tmp = new ArrayList<ExportHeadDTO>();
                        if (gridFields2 != null && gridFields2.size() > 0){
                            fields2Flag[0] = false;
                            gridFields2.stream().forEach(gridField -> {
                                ExportHeadDTO exportHeadDTO2 = new ExportHeadDTO();
                                exportHeadDTO2.setName(gridField.getField()).setText(gridField.getLabel()).setQueryType(gridField.getQueryType()).setDict(gridField.getDict()).setHead2(true);

                                // if (exportHeadDTOList2.size() == 0) leftEmptyColNum[0]++;

                                exportHeadDTOList2.add(exportHeadDTO2);
                                exportHeadDTOList2Tmp.add(exportHeadDTO2);
                            });
                            exportHeadDTO1.setColspan(gridFields2.size());

                            exportHeadDTOListAll.addAll(exportHeadDTOList2Tmp);
                        }else {
                            if (fields2Flag[0]) leftEmptyColNum[0]++;
                            exportHeadDTOListAll.add(exportHeadDTO1);
                        }
                        exportHeadDTOList1.add(exportHeadDTO1);
                    });
                }
            } else {
                //表头列
                for (GridField gridField : gridFields) {
                    if (gridField.getFlagShow() == null || !gridField.getFlagShow()) continue;
                    exportHeadDTO = new ExportHeadDTO();
                    exportHeadDTO.setName(gridField.getField()).setText(gridField.getLabel()).setQueryType(gridField.getQueryType()).setDict(gridField.getDict());
                    exportHeadDTOList1.add(exportHeadDTO);
                    exportHeadDTOListAll.add(exportHeadDTO);
                }
            }

            exporDataList = fetchResult.getData();
            exporSumDataList = fetchResult.getSumData();




            sheetName = config.getName();
            fileName = config.getName() + "_" + DateUtils.format(new Date(), "yyyyMMddHHmmss");
            fileNameAll = fileName + ".xls";
        }

        String downloadPath = "download/" + fileNameAll;
        String tmpFilePath = resPath + downloadPath;
        String dirPath = resPath + "download";
        FileUtils.mkdirs(resPath + "download");
        File tmpFile = new File(tmpFilePath);
        logger.debug("tmpFilePath={}", tmpFilePath);

        //工作表
        if (exporDataList.size() > 5000) {
            int sheetIndex = 0;
            for(List<Map<String, Object>> listSub : CollectionUtil.split(exporDataList, 5000)) {
                exportService.exportReport(config,workbook, StrUtil.format("{}({}-{}行)",sheetName,5000 * sheetIndex + 1,(5000 * sheetIndex + 1) + listSub.size()),exportHeadDTOListAll,exporSumDataList,exportHeadDTOList1,exportHeadDTOList2,listSub,exportFooterSumArr,exportFooterSignArr);
                sheetIndex++;
            }
        } else {
            exportService.exportReport(config,workbook, StrUtil.format("{}(1-{}行)",sheetName,exporDataList.size()),exportHeadDTOListAll,exporSumDataList,exportHeadDTOList1,exportHeadDTOList2,exporDataList,exportFooterSumArr,exportFooterSignArr);
        }


        OutputStream os = null;
        try {
            os = new FileOutputStream(tmpFile);
            workbook.write(os);
            restResult.setData(downloadPath);
        } catch (IOException e) {
            restResult.setMsg("操作失败，原因:" + e.getMessage());
            restResult.setCode(ErrorCode.COMMON_ERROR);
        }
        return restResult;
    }

    /**
     * @param tableName : 表名称
     * @param pkValue   : 主键值
     * @Description：更新标签打印数量即最近打印时间，打印时间字段固定为 printTime
     */
    @GetMapping(value = "updateFormPrintTime/{tableName}/{pkName}/{pkValue}")
    public RestResult updateFormPrintTime(@PathVariable String tableName, @PathVariable String pkName, @PathVariable String pkValue) {
        RestResult restResult = RestResult.ok();
        if (StringUtils.isNotBlank(tableName) && StringUtils.isNotBlank(pkName) && StringUtils.isNotBlank(pkValue)) {
            jdbcTemplate.update("update " + tableName + "  set print_time = '" + DateUtils.getDate(new Date()) + "',flag_print = 1 where " + pkName + " = '" + pkValue + "'");
        }

        return restResult;
    }

    /**
     * 数据视图-导入数据
     */
    @GetMapping("/importData")
    synchronized public RestResult importData(HttpServletResponse response, HttpServletRequest request, @RequestParam Map<String, String> reqData) throws Exception {
        logger.info("Tool.import.开始");
        RestResult restResult = RestResult.ok();
        //导入模板视图标识
        String importViewKey = reqData.get("importViewKey");
        //已上传文件路径
        String filePath = reqData.get("filePath");
        String opType = reqData.get("opType");
        String importStamp = reqData.get("importStamp");

        String viewString = CacheUtils.get(CacheUtils.DATAVIEW_CACHE, importViewKey) + "";
        JSONObject dataViewOb = JSONObject.parseObject(viewString);
        JSONArray columnsArr = dataViewOb.getJSONArray("columns");//数据视图dataView定义的列信息的JSON数组
        String tempTableName = "import_temp_" + importViewKey, sql;


        if (opType.equals("1")) { //1：从已上传文件导入到临时表
            BusinessException.throwErrorIf(true, "此方法已经废弃");
            importStamp = DateUtils.format(new Date(), "yyyyMMddHHmmss");
            restResult.setMsg(ImportService.addTmpTableDataFromExcel(filePath, tempTableName, importStamp, columnsArr, dataViewOb));
        } else if (opType.equals("2")) { //2:从临时表导入到正式表
            BusinessException.throwErrorIf(true, "此方法已经废弃");
            restResult.setMsg(ImportService.addTableDataFromTmpTable(filePath, tempTableName, importStamp, columnsArr, dataViewOb));
        } else if (opType.equals("3")) {//3:删除本次导入临时表数据
            BusinessException.throwErrorIf(true, "此方法已经废弃");
            jdbcTemplate.execute("delete from " + tempTableName + " where   import_stamp ='" + importStamp + "'");
            importStamp = null;
        }
        logger.info("Tool.import.结束");
        restResult.setData(importStamp);
        return restResult;
    }

    /**
     * 数据视图-通过Excel导入数据
     */
    @GetMapping("/importExcelData")
    synchronized public RestResult importExcelData(HttpServletResponse response, HttpServletRequest request, @RequestParam Map<String, String> reqData) throws Exception {
        logger.info("Tool.import.开始");
        RestResult restResult = RestResult.ok();
        //导入模板视图标识
        String importViewKey = reqData.get("importViewKey");
        //已上传文件路径
        String filePath = reqData.get("filePath");
        String opType = reqData.get("opType");
        String importStamp = reqData.get("importStamp");

        String viewString = CacheUtils.get(CacheUtils.DATAVIEW_CACHE, importViewKey) + "";
        JSONObject dataViewOb = JSONObject.parseObject(viewString);
        JSONArray columnsArr = dataViewOb.getJSONArray("columns");//数据视图dataView定义的列信息的JSON数组
        String tempTableName = "import_temp_" + importViewKey, sql;


        if (opType.equals("1")) { //1：从已上传文件导入到临时表
            importStamp = DateUtils.format(new Date(), "yyyyMMddHHmmss");
            restResult.setMsg(ImportService.addTmpTableDataFromExcel(filePath, tempTableName, importStamp, columnsArr, dataViewOb));
        } else if (opType.equals("2")) { //2:从临时表导入到正式表
            restResult.setMsg(ImportService.addTableDataFromTmpTable(filePath, tempTableName, importStamp, columnsArr, dataViewOb));
        } else if (opType.equals("3")) {//3:删除本次导入临时表数据
            jdbcTemplate.execute("delete from " + tempTableName + " where   import_stamp ='" + importStamp + "'");
            importStamp = null;
        }
        logger.info("Tool.import.结束");
        restResult.setData(importStamp);
        return restResult;
    }

    /**
     * 数据视图-导出数据模板（下载导入模板）
     */
    @PostMapping("/exportTemplate")
    public RestResult exportTemplate(HttpServletResponse response, HttpServletRequest request, @RequestBody Map<String, String> reqData) throws Exception {
        logger.info("Tool.exportTemplate.开始");
        RestResult restResult = RestResult.ok();

        QueryContext queryContext = QueryContextHolder.currentContext();
        queryContext.setParams(Maps.newHashMap()).setPage(new Page()).setWrapper(new QueryWrapper());
        queryContext.getWrapper().eq("1", "0");

        ExportParams exportParams = JSON.parseObject(JSON.toJSONString(reqData), ExportParams.class);
        Map<String, Object> userParam = null;
        //固定参数
        if (reqData.containsKey("userParam")) {
            JSONObject ob = JSON.parseObject(reqData.get("userParam") + "");
            userParam = Maps.newHashMap(ob);
        }
        restResult.setData(service.exportFullData(queryContext, exportParams, userParam));

        logger.info("Tool.exportTemplate.结束");
        return restResult;
    }

    /**
     * @param reportKey : 报表标识
     * @Description：清空并刷新报表临时表
     */
    @GetMapping(value = "reportTempTableClear/{reportKey}")
    public RestResult reportTempTableClear(@PathVariable String reportKey) {
        RestResult restResult = RestResult.ok();
        Config config = configService.getOne(Wrappers.<Config>query().eq("code", reportKey));
        synchronized (config) {
            try {
                jdbcTemplate.execute("drop table " + "report_temp_" + config.getCode());
            } catch (Exception e) {
            }
            CommonService.reportTempTable(config, true);
        }
        return RestResult.ok();
    }


    /**
     * 获取数据列表，导入时临时表查询使用
     */
    @GetMapping("/pageForImportTmpTable")
    public RestResult pageForImportTmpTable(@RequestParam Map<String, String> reqData) {
        String importTableName = reqData.get("importTableName");
        String importStamp = "-1";

        Map<String, String> userParam = null;
        //固定参数8
        if (reqData.containsKey("userParam")) {
            JSONObject ob = JSON.parseObject(reqData.get("userParam") + "");
            importStamp = ob.getString("importStamp");
        }
        String queryString = reqData.get("queryString");
        String SqlWhere = "";
        if (StringUtils.isNotBlank(queryString)) {
            SqlWhere = QueryGenerator.getSqlWhere(queryString);
            if (StringUtils.isNotBlank(SqlWhere)) SqlWhere = " and " + SqlWhere;
        }

        Map mapTempTable = null;
        try {
            mapTempTable = jdbcTemplate.queryForMap(" select * from " + importTableName + "  limit 1   ");
        } catch (Exception e) {
        }
        //有数据时，转换成驼峰字段
        List<Map<String, Object>> dataList = null;
        if (mapTempTable != null) {
            List<String> fieldList = new ArrayList<String>();
            mapTempTable.keySet().stream().forEach(field -> {
                fieldList.add(field + " as " + StringUtils.underline2Camel(field + "", true));
            });

            dataList = jdbcTemplate.queryForList("select " + StringUtils.join(fieldList, ",") + " from " + importTableName + " where import_stamp='" + importStamp + "' " + SqlWhere);
        }

        return RestResult.ok("查询成功", dataList);
    }


    /**
     * 数据视图-批量同步数据
     */
    @GetMapping("/syncBatchFromDataview")
    synchronized public RestResult syncBatchFromDataview(String viewKeys) throws Exception {
        logger.info("Tool.syncBatchFromDataview.开始");
        RestResult restResult = RestResult.ok(ImportService.syncBatchFromDataview(viewKeys.split(",")));
        return restResult;
    }


    /**
     * 下载文件 根据绝对路径
     * @param response
     */
    @RequestMapping("downloadAbfile")
    @ResponseBody
    public void downloadAbfile(HttpServletResponse response,String fileAbPath,String fileName) {
        File path = null;
        response.setHeader("content-type", "application/octet-stream");
        response.setContentType("application/octet-stream");
        try {
            response.setHeader("Content-Disposition", "attachment;filename=" + java.net.URLEncoder.encode(fileName, "UTF-8"));
        } catch (UnsupportedEncodingException e2) {
            e2.printStackTrace();
        }
        byte[] buff = new byte[1024];
        BufferedInputStream bis = null;
        OutputStream os = null;
        try {
            os = response.getOutputStream();
            File file = new File(fileAbPath);
            bis = new BufferedInputStream(new FileInputStream(file));
            int i = bis.read(buff);
            while (i != -1) {
                os.write(buff, 0, buff.length);
                os.flush();
                i = bis.read(buff);
            }
        } catch (ClientAbortException e1) { //中止连接不做处理
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (bis != null) {
                try {
                    bis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
